//
// Created by delin10 on 2020/5/4.
//
#include <stdio.h>
#include <poll.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <zconf.h>
#include <bits/signum.h>
#include <signal.h>
#include <fcntl.h>
#include "sys/select.h"
#include "errno.h"
#include "../../utils/debug.h"
#include "../../utils/net/sock_utils.h"

typedef void (*fd_consumer)(int);

void consume_fd(int fd) {
    int n = 0;
    char buf[1024];
    while ((n = read(fd, buf, 1023)) > 0) {
        buf[n] = '\0';
        printf("%s", buf);
    }
}

int test_select(fd_consumer consumer) {
    char ip[] = "127.0.0.1";
    int listen_fd = open_server_socket(ip, 13010);
    if (listen_fd < 0) {
        return -1;
    }
    signal(SIGPIPE, SIG_IGN);
    fd_set read_fds, all_fds;
    socklen_t addr_size = sizeof(struct sockaddr_in);
    struct sockaddr_in in;
    int n;
    int count;
    char buf[1024];
    int max_clients = FD_SETSIZE;
    int fd_array[max_clients];
    for (int i = 0; i < max_clients; ++i) {
        fd_array[i] = -1;
    }
    char hello_buf[] = "hello from server";
    int max_fd = listen_fd;
    int max_index = -1;

    FD_ZERO(&all_fds);
    FD_SET(listen_fd, &all_fds);

    while (1) {
        read_fds = all_fds;
        count = select(max_fd + 1, &read_fds, NULL, NULL, NULL);


        if (count < 0) {
            d_log_err("errno = %d, desc = %s\n", errno, strerror(errno));
        } else if (count > 0) {
            printf("select socket count = %d\n", count);
            if (FD_ISSET(listen_fd, &read_fds)) {
                int in_fd = accept(listen_fd, (struct sockaddr *) &in, &addr_size);
                printf("in ip = %s\n", inet_ntoa(in.sin_addr));
                int i = 0;
                for (; i < max_clients; ++i) {
                    if (fd_array[i] < 0) {
                        fd_array[i] = in_fd;
                        break;
                    }
                }

                if (i == max_clients) {
                    d_log_err("Too many clients");
                    return -1;
                }

                if (i > max_index) {
                    max_index = i;
                }

                if (in_fd > max_fd) {
                    max_fd = in_fd;
                }

                fcntl(in_fd, F_SETFD, O_NONBLOCK);
                FD_SET(in_fd, &all_fds);

                if (--count <= 0) {
                    continue;
                }
            }

            for (int j = 0; j <= max_index; ++j) {
                int fd = fd_array[j];

                if (fd < 0) {
                    continue;
                }

                if (FD_ISSET(fd, &read_fds)) {
                    printf("Has Sock listen_fd = %d\n", j);
                    if ((n = read(fd, buf, 1024)) > 0) {
                        printf("接收到数据：%d字节\n", n);
                        printf("%s\n", buf);
                        ssize_t send_n = write(fd, hello_buf, strlen(hello_buf));
                        printf("Send to client %d ok with byte count = %zd\n", fd, send_n);
                    } else if (n == EOF) {
                        FD_CLR(fd, &all_fds);
                        fd_array[j] = -1;
                        close(fd);
                        d_log_err("连接断开：%d", fd);
                    } else {
                        d_log_err("出现错误：%d", fd);
                        FD_CLR(fd, &all_fds);
                        fd_array[j] = -1;
                        close(fd);
                    }
                    if (--count <= 0) {
                        break;
                    }
                }
            }
        }
    }
    return 0;
}

#define OPEN_MAX 1024
int test_poll() {
    char ip[] = "127.0.0.1";
    int listen_fd = open_server_socket(ip, 13010);
    if (listen_fd < 0) {
        return -1;
    }
    signal(SIGPIPE, SIG_IGN);
    struct pollfd client_arr[OPEN_MAX];
    socklen_t addr_size = sizeof(struct sockaddr_in);
    struct sockaddr_in in;
    int n;
    int count;
    char buf[1024];
    int max_clients = FD_SETSIZE;
    int fd_array[max_clients];
    for (int i = 0; i < max_clients; ++i) {
        fd_array[i] = -1;
    }
    char hello_buf[] = "hello from server";
    int max_index = 0;

    client_arr[0].fd = listen_fd;
    client_arr[0].events = POLLRDNORM; //普通数据可读
    while (1) {
        count = poll(client_arr, max_index + 1, -1);


        if (count < 0) {
            d_log_err("errno = %d, desc = %s\n", errno, strerror(errno));
        } else if (count > 0) {
            printf("select socket count = %d\n", count);
            if (client_arr[0].revents & POLLRDNORM) {
                int in_fd = accept(listen_fd, (struct sockaddr *) &in, &addr_size);
                printf("in ip = %s\n", inet_ntoa(in.sin_addr));
                int i = 0;
                for (; i < OPEN_MAX; ++i) {
                    if (client_arr[i].fd < 0) {
                        client_arr[i].fd = in_fd;
                        break;
                    }
                }

                if (i == OPEN_MAX) {
                    d_log_err("Too many clients");
                    return -1;
                }

                client_arr[i].events = POLLRDNORM;

                if (i > max_index) {
                    max_index = i;
                }


                if (--count <= 0) {
                    continue;
                }
            }

            for (int j = 0; j <= max_index; ++j) {
                int fd = client_arr[j].fd;

                if (fd < 0) {
                    continue;
                }

                if (client_arr[j].revents & (POLLRDNORM | POLLERR)) {
                    if ((n = read(fd, buf, 1024)) > 0) {
                        printf("接收到数据：%d字节\n", n);
                        printf("%s\n", buf);
                        ssize_t send_n = write(fd, hello_buf, strlen(hello_buf));
                        printf("Send to client %d ok with byte count = %zd\n", fd, send_n);
                    } else if (n == EOF) {
                        client_arr[j].fd = -1;
                        close(fd);
                        d_log_err("连接断开：%d", fd);
                    } else {
                        if (errno == ECONNRESET) {
                            close(fd);
                            client_arr[j].fd = -1;
                        } else {
                            close(fd);
                            client_arr[j].fd = -1;
                            d_log_err("出现错误：%d", fd);
                        }
                    }
                    if (--count <= 0) {
                        break;
                    }
                }
            }
        }
    }
    return 0;
}
#define MAX_EVENTS 10
int test_epoll() {
    char ip[] = "127.0.0.1";
    int listen_fd = open_server_socket(ip, 13011);
    if (listen_fd < 0) {
        return -1;
    }
    signal(SIGPIPE, SIG_IGN);
    struct pollfd client_arr[OPEN_MAX];
    socklen_t addr_size = sizeof(struct sockaddr_in);
    struct sockaddr_in in;
    int n;
    int count;
    char buf[1024];
    char hello_buf[] = "hello from server";
    int max_clients = FD_SETSIZE;
    int epollfd = epoll_create1(0);
    if (epollfd == -1) {
        perror("epoll_create1");
        return -1;
    }
    struct epoll_event ev, events[MAX_EVENTS];
    ev.events = EPOLLIN;
    ev.data.fd = listen_fd;
    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_fd, &ev) == -1) {
        perror("epoll_ctl: listen_fd");
        return -1;
    }

    int nfds;
    for (;;) {
        nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
        if (nfds == -1) {
            perror("epoll_wait");
            printf("error: %s", strerror(errno));
            return -1;
        }

        for (n = 0; n < nfds; ++n) {
            int fd = events[n].data.fd;
            if (fd == listen_fd) {
                int in_fd = accept(listen_fd,
                                   (struct sockaddr *) &in, &addr_size);
                if (in_fd == -1) {
                    perror("accept");
                    print_errno_msg();
                    return -1;
                }
                setnonblocking(in_fd);
                ev.events = EPOLLIN | EPOLLET;
                ev.data.fd = in_fd;
                if (epoll_ctl(epollfd, EPOLL_CTL_ADD, in_fd,
                              &ev) == -1) {
                    perror("epoll_ctl: conn_sock");
                    return -1;
                }
            } else {
                int bytes;
                if (events[n].events & EPOLLIN) {
                    while ((bytes = read(fd, buf, 1)) > 0) {
                        buf[1] = '\0';
                        printf("%s", buf);
                    }
                    ssize_t send_n = write(fd, hello_buf, strlen(hello_buf));
                }
            }
        }
    }
    
}

int main(int argc, char *argv[]) {
    return test_epoll();
}

int test_accept() {
    char ip[] = "127.0.0.1";
    int fd = open_server_socket(ip, 13010);
    if (fd < 0) {
        return -1;
    }
    struct sockaddr_in in;
    int n;
    char buf[1024];
    socklen_t addr_size = sizeof(struct sockaddr_in);

    while (1) {
        int in_fd = accept(fd, &in, &addr_size);
        d_log_err("%d", in_fd);
        d_log_err(inet_ntoa(in.sin_addr));
        if (in_fd > 0) {
            while ((n = recv(in_fd, buf, 1024, 0)) > 0) {
                printf("%s", buf);
            }
            printf("\n");
        } else {
            d_log_err("errno = %d, desc = %s\n", errno, strerror(errno));
            break;
        }
    }
    return 0;
}


